package com.evolved.automata.android.bots.speechbot;
import java.util.*;

import android.util.*;
import com.evolved.automata.*;
import com.evolved.automata.inference.*;

import android.database.*;
import android.database.sqlite.*;
import android.content.*;
import java.util.*;
import android.content.res.*;
import android.os.*;



public class DataAccessApparatus 
{
	
	StructureModel model;
	StructureModel questionModel;
	
	
	String dbName;
	SQLiteDatabase dataBase;
	PermanentStorageTable structureMapTable;
	TemplateTable templateTable;
	String[] labelList;
	Hashtable<String, Bundle> labelMap;
	
	
	Context context;
	boolean firstTime;
	int structureSize;
	public final static String questionFilterKey="Question1";
	public final static String questionKeyName="QuestionKey";
	
	public DataAccessApparatus(Context context, int size, String databaseName, boolean initialLoad)
	{
		structureSize=size;
		this.context=context;
		dbName=databaseName;
		model = new StructureModel(structureSize);
		dataBase = StandardTools.getDataBase(context, dbName);
		firstTime=initialLoad;
		initializeDatabase();
		reloadModel();
		questionModel = new StructureModel(size);
		
	}
	
	
	public void loadQuestionModel()
	{
		KeyValuePair[] questionKeys=null;
		String[] values;
		int counter=0;
		KeyValuePair[] structureValues;
		
		
		for (String keyWord:model.GetKeys())
		{
			values=model.GetValuesForKey(keyWord);
			for (String keyValue:values)
			{
				if (keyValue.equals(questionFilterKey))
				{
					
					questionKeys=convertQuestionToKeys(keyWord);
					structureValues = new KeyValuePair[questionKeys.length+1];
					counter=1;
					structureValues[0]=new KeyValuePair(questionKeyName,keyWord);;
					for (KeyValuePair qKey:questionKeys)
					{
						structureValues[counter++]= qKey;
					}
					questionModel.AddObservation(structureValues);
				}
			}
			
		}
	}
	
	public void addQuestionToModel(String questionText)
	{
		
		List<StructureSlice> consistentWorlds=null;
	}
	
	private KeyValuePair[] convertQuestionToKeys(String questionText)
	{
		HashSet<String> qSet = new HashSet<String>();
		String[] questionKeys=null;
		questionKeys=StandardTools.splitCommaDelimitedString(questionText, ' ');
		LinkedList<KeyValuePair> keyValuePairs = new LinkedList<KeyValuePair>();
		
		for (String keyWord:questionKeys)
		{
			if (!qSet.contains(keyWord))
			{
				keyValuePairs.add(new KeyValuePair(keyWord,"Question"));
				qSet.add(keyWord);
			}
		}
		return keyValuePairs.toArray(new KeyValuePair[0]);
	}
	
	public String[] identifyQuestion(String questionText)
	{
		
		LinkedList<String> applicableWords = new LinkedList<String>();
		String[] questionWords = StandardTools.splitCommaDelimitedString(questionText, ' ');
		String[] values=null;
		HashSet<String> qSet = new HashSet<String>();
		for (String questionWord:questionWords)
		{
			values=questionModel.GetValuesForKey(questionWord);
			if ((values.length>0)&&(!qSet.contains(questionWord)))
			{
				applicableWords.add(questionWord);
				qSet.add(questionWord);
			}
		}
		
		if (applicableWords.size()==0)
			return null;
		int counter=0;
		KeyValuePair[] questionKeys = new KeyValuePair[applicableWords.size()];
		for (String questionKey:applicableWords)
		{
			questionKeys[counter++] = new KeyValuePair(questionKey, "Question");
		}
		
		List<StructureSlice> inferredQuestions=null;
		
		inferredQuestions = questionModel.GetConsistentSlices(questionKeys, 1.0, 0.0,true);
		String[] questions = new String[inferredQuestions.size()];
		int i=0;
		String v=null;
		for (StructureSlice slice:inferredQuestions)
		{
			v=slice.GetValue(questionKeyName);
			if (v!=null)
				questions[i++]=v;
		}
		return questions;
	}
	
	
	public String[] getConsistentWorlds(Hashtable<String, String> keyValueMap)
	{
		KeyValuePair[] keyValuePairs = StandardTools.parseToKeyValuePairsFromString(keyValueMap);
		List<StructureSlice> results=model.GetConsistentSlices(keyValuePairs, 1.0, 0.0);
		String[] serializedWorlds = new String[results.size()];
		
		int counter=0;
		for (StructureSlice slice:results)
		{
			serializedWorlds[counter++]=StandardTools.serializeToString(
					StandardTools.parseToKeyValueMapFromKeyValuePairs(slice.GetKeyValuePairs()));
		}
		return serializedWorlds;
	}
	
	
	public String[] getConsistentWorlds(Hashtable<String, String> keyValueMap, boolean strictP)
	{
		KeyValuePair[] keyValuePairs = StandardTools.parseToKeyValuePairsFromString(keyValueMap);
		List<StructureSlice> results=model.GetConsistentSlices(keyValuePairs, 1.0, 0.0,strictP);
		String[] serializedWorlds = new String[results.size()];
		
		int counter=0;
		for (StructureSlice slice:results)
		{
			serializedWorlds[counter++]=StandardTools.serializeToString(
					StandardTools.parseToKeyValueMapFromKeyValuePairs(slice.GetKeyValuePairs()));
		}
		return serializedWorlds;
	}
	
	
	public String[] getAllWorlds()
	{
		List<StructureSlice> results=model.GetAllWorlds();
		String[] serializedWorlds = new String[results.size()];
		
		int counter=0;
		for (StructureSlice slice:results)
		{
			serializedWorlds[counter++]=StandardTools.serializeToString(
					StandardTools.parseToKeyValueMapFromKeyValuePairs(slice.GetKeyValuePairs()));
		}
		return serializedWorlds;
	}
	
	
	public List<Integer> getConsistentWorldIndices(Hashtable<String, String> keyValueMap)
	{
		KeyValuePair[] keyValuePairs = StandardTools.parseToKeyValuePairsFromString(keyValueMap);
		
		return model.GetConsistentWorlds(keyValuePairs, 1.0, 0.0);
	}
	
	/* Start */
	
	public boolean deleteConsistentWorldIndices(List<Integer> worlds)
	{
		
		boolean deleted=false;
		for (Integer modelKey: worlds)
		{
			deleted = deleted || model.DeleteWorldsExplicit(modelKey.intValue());
			structureMapTable.deleteModel(modelKey.intValue());
		}
		
		return deleted;
	}
	
	
	public int processChangedKeyValueIndices(List<Integer> worlds, String keyName, String keyValue)
	{
		List<Integer> results = model.UpdateKeyValuesInAllConsistentWorlds(worlds, keyName, keyValue);
		return results.size();
	}
	
	public int addKeyValueToConsistentWorldIndices(List<Integer> worlds, String keyName, String keyValue)
	{
		
		List<Integer> results = model.AddKeyValuesToAllConsistentWorlds(worlds, keyName, keyValue);
		return results.size();
	}
	
	public int removeKeyValueFromConsistentWorldIndices(List<Integer> worlds, String keyName)
	{
		List<Integer> results = model.RemoveKeyFromConsistentWorlds(worlds, keyName);
		return results.size();
	}
	
	
	public boolean deleteConsistentWorlds(Hashtable<String, String> keyValueMap)
	{
		KeyValuePair[] keyValuePairs = StandardTools.parseToKeyValuePairsFromString(keyValueMap);
		Integer[] deleted=model.DeleteWorlds(keyValuePairs);
		for (Integer modelKey: deleted)
		{
			structureMapTable.deleteModel(modelKey.intValue());
		}
		
		return deleted.length>0;
	}
	
	
	public int processChangedKeyValue(Hashtable<String,String> keyValuePairs, String keyName, String keyValue)
	{
		KeyValuePair[] pairs = StandardTools.parseToKeyValuePairsFromString(keyValuePairs);
		List<Integer> results = model.UpdateKeyValuesInAllConsistentWorlds(pairs, keyName, keyValue);
		return results.size();
	}
	
	public int addKeyValueToConsistentWorlds(Hashtable<String,String> keyValuePairs, String keyName, String keyValue)
	{
		KeyValuePair[] pairs = StandardTools.parseToKeyValuePairsFromString(keyValuePairs);
		List<Integer> results = model.AddKeyValuesToAllConsistentWorlds(pairs, keyName, keyValue);
		return results.size();
	}
	
	public int removeKeyValueFromConsistentWorlds(Hashtable<String,String> keyValuePairs, String keyName)
	{
		KeyValuePair[] pairs = StandardTools.parseToKeyValuePairsFromString(keyValuePairs);
		List<Integer> results = model.RemoveKeyFromConsistentWorlds(pairs, keyName);
		return results.size();
	}
	
	
	/* Finish */
	
	
	public boolean storeKeyValueMap(Hashtable<String, String> keyValueMap)
	{
		int newKey;
		if (keyValueMap.size()>0)
		{
			String serialized = StandardTools.serializeToString(keyValueMap);
			newKey=addToModel(serialized);
			if (newKey>=0)
			{
				loadToPermanentStorage(serialized,newKey);
				return true;
			}
		}
		return false;
	}
	
	// This modifies the original hashmap
	public Hashtable<String, String> executeInferenceQuery(Hashtable<String, String> keyValueMap)
	{
		if (keyValueMap.size()==0)
			return keyValueMap;
		
		String[] queryList;
		queryList = StandardTools.extractQueryList(keyValueMap);
		
		// removes query keys from keyValueMap, leaving only evidence variables behind
		if ((keyValueMap.size()==0)||(queryList.length==0))
			return keyValueMap;
		
		
		KeyValuePair[] pairs = StandardTools.parseToKeyValuePairsFromString(keyValueMap);
		HashMap<String, HashMap<String, Double>> results;
		results = model.OptimizedInference(pairs, queryList, 1.0, 0.0);
		
		HashMap<String, ProbabilityDistribution<String>> probDistributionSet;
		probDistributionSet = StructureModel.MapToProbabilityDistributionMap(results);
		
		ProbabilityDistribution<String> probabilityDistrib;
		for (String queryName:queryList)
		{
			if (probDistributionSet.containsKey(queryName))
			{	
				probabilityDistrib = probDistributionSet.get(queryName);
				keyValueMap.put(queryName, probabilityDistrib.GenerateValue());
			}
			else
				keyValueMap.put(queryName, "");
		}
		
		return keyValueMap;
	}
	
	public Hashtable<String, String> executeInferenceQuery(Hashtable<String, String> evidenceMap, String[] queryKeys)
	{
		if (evidenceMap.size()==0)
			return evidenceMap;
		
		
		
		// removes query keys from keyValueMap, leaving only evidence variables behind
		if (queryKeys.length==0)
			return evidenceMap;
		
		
		KeyValuePair[] pairs = StandardTools.parseToKeyValuePairsFromString(evidenceMap);
		HashMap<String, HashMap<String, Double>> results;
		results = model.OptimizedInference(pairs, queryKeys, 1.0, 0.0);
		
		HashMap<String, ProbabilityDistribution<String>> probDistributionSet;
		probDistributionSet = StructureModel.MapToProbabilityDistributionMap(results);
		
		ProbabilityDistribution<String> probabilityDistrib;
		for (String queryName:queryKeys)
		{
			if (probDistributionSet.containsKey(queryName))
			{	
				probabilityDistrib = probDistributionSet.get(queryName);
				evidenceMap.put(queryName, probabilityDistrib.GenerateValue());
			}
			else
				evidenceMap.put(queryName, "");
		}
		
		return evidenceMap;
	}
	
	public String[] getAllKeys()
	{
		if (model==null)
			return new String[0];
		else
			return model.GetKeys();
	}
	
	public Bundle[] getAllStructuresFromDB()
	{
		return structureMapTable.selectAllStructures();
	}
	
	public String[] getValuesForKey(String key)
	{
		if (model==null)
			return new String[0];
		else
			return model.GetValuesForKey(key);
	}


	
	public void reloadModel()
	{
		Bundle[] mapList=retrieveDataFromPermanentStorage();
		KeyValuePair[] pairs;
		String serializedData;
		int originalModelIndex=0;
		Integer newIndex;
		for (Bundle dataRow:mapList)
		{
			serializedData = dataRow.getString("structure");
			originalModelIndex=dataRow.getInt("model_id");
			pairs = StandardTools.parseToKeyValuePairsFromString(serializedData);
			newIndex=model.AddObservation(pairs,originalModelIndex);
			//TODO: don't do this.  figure out how to get rid of duplicates
//			if (newIndex==null)
//				throw new RuntimeException("Failure to reload model");
		}
	}
	
	public void clearPermanentStorage()
	{
		structureMapTable.clear();
		// TODO: Make something more efficient than this because this will engage the garbage collector
		model=null;
		model = new StructureModel(structureSize);
	}
	
	public void clearAllTemplates()
	{
		templateTable.clear();
		labelMap.clear();
	}
	
	public void removeTemplate(String label)
	{
		templateTable.deleteTemplate(label);
		if (labelMap.containsKey(label))
			labelMap.remove(label);
	}
	
	public String[] getAllTemplateLabels()
	{
		String[] labels = new String[labelMap.size()];
		int counter=0;
		Bundle dataRow;
		
		for (String labelKey:labelMap.keySet().toArray(new String[0]))
		{
			dataRow = labelMap.get(labelKey);
			labels[counter++]=dataRow.getString("label");
		}
		return labels;
	}
	
	public void synchronizeModelWithDB(List<Integer> modelKeys)
	{
		StructureSlice slice;
		String serializedForm;
		for (Integer modelKey:modelKeys)
		{
			slice=model.GetSliceExplicit(modelKey);
			if (slice!=null)
			{
				serializedForm = StandardTools.serializeToString(slice.GetKeyValuePairs());
				structureMapTable.updateStructure(serializedForm, modelKey.intValue());
			}
		}
	}
	
	public boolean addNewTemplate(boolean exportDataP, int labelType, String labelName, String structure, String data_to_export)
	{
		if (labelMap.containsKey(labelName))
			return false;
		templateTable.insertData(labelType, labelName, structure, exportDataP, data_to_export);
		
		Bundle dataRow = getDataBundle(exportDataP,labelType,labelName,structure,data_to_export);
		labelMap.put(labelName, dataRow);
		return true;
	}
	
	private Bundle getDataBundle(boolean exportDataP, int labelType, String labelName, String structure, String data_to_export)
	{
		Bundle newData = new Bundle();
		newData.putString("structure", structure);
		newData.putString("export_data", data_to_export);
		newData.putString("label", labelName);
		newData.putInt("type", labelType);
		newData.putInt("export_to_stack", (exportDataP)?1:0);
		return newData;
	}
	
	public boolean templateLabelExistsP(String templateName)
	{
		return labelMap.containsKey(templateName);
	}
	
	public boolean updateTemplate(boolean exportDataP, int labelType, String labelName, String structure, String data_to_export)
	{
		if (!labelMap.containsKey(labelName))
			return false;
		templateTable.deleteTemplate(labelName);
		templateTable.insertData(labelType, labelName, structure, exportDataP, data_to_export);
		Bundle dataRow = getDataBundle(exportDataP,labelType,labelName,structure,data_to_export);
		labelMap.put(labelName, dataRow);
		return true;
	}
	
	public Bundle[] selectAllLabelData(String label)
	{
		return templateTable.selectLabelData(label);
	}
	
	
	private void loadAllLabels()
	{
		labelMap = new Hashtable<String, Bundle>();
		Bundle[] labelRecordSet = templateTable.selectAllData();
		String labelName;
		for (Bundle dataRow:labelRecordSet)
		{
			labelName = dataRow.getString("label");
			labelMap.put(labelName, dataRow);
		}
	}
	private void initializeDatabase()
	{
		structureMapTable = new PermanentStorageTable();
		templateTable = new TemplateTable();
		if (firstTime)
		{
			structureMapTable.create();
			templateTable.create();
		}
		loadAllLabels();
	}
	
	private void loadToPermanentStorage(String serialized, int modelKey)
	{
		structureMapTable.insertData(serialized,modelKey);
	}
	
	
	private int addToModel(String serializedMap)
	{
		Integer newKey=null;
		KeyValuePair[] pairs = StandardTools.parseToKeyValuePairsFromString(serializedMap);
		newKey=model.AddObservation(pairs);
		if (newKey==null)
			return -1;
		else
			return newKey.intValue();
	}
	
	private Bundle[] retrieveDataFromPermanentStorage()
	{
		return structureMapTable.selectAllStructures();
	}
	

	

	
	
	private class PermanentStorageTable
	{
		
		Resources resources;
		String r_CreateScript;
		String r_ClearTableScript;
		String r_InsertDataQuery;
		String r_TableName;
		String r_DeleteModelScript;
		String[] r_SelectColumns;
		int r_StructureColumnIndex;
		String r_UpdateStructureScriptPattern;
		
		public PermanentStorageTable()
		{
			resources=context.getResources();
			r_CreateScript = resources.getString(R.string.struct_tb_create_sql);
			r_ClearTableScript=resources.getString(R.string.struct_tb_drop_sql);
			r_InsertDataQuery = resources.getString(R.string.struct_tb_insert_sql);
			r_StructureColumnIndex=resources.getInteger(R.integer.struct_column_index);
			r_SelectColumns = resources.getStringArray(R.array.db_structure_column_names);
			r_TableName = resources.getString(R.string.struct_tb_name);
			r_DeleteModelScript=resources.getString(R.string.struct_tb_delete_model_sql);
			r_UpdateStructureScriptPattern=resources.getString(R.string.struct_update_structure_sql);
		}
		
		public void create()
		{
			executeNonQuery(r_CreateScript);
		}
		
		public void clear()
		{
			executeNonQuery(r_ClearTableScript);
		}
		
		public void updateStructure(String serializedStructure, int model_id)
		{
			String updateScript = String.format(r_UpdateStructureScriptPattern, StandardTools.escapeDBString(serializedStructure),model_id);
			executeNonQuery(updateScript);
		}
		
		public void deleteModel(int modelKey)
		{
			String deleteScript = String.format(r_DeleteModelScript, modelKey);
			executeNonQuery(deleteScript);
		}
		public void insertData(String structureRow, int modelKey)
		{
			String insertStatement=null;
			try
			{
				insertStatement = String.format(r_InsertDataQuery, StandardTools.getCurrentDateInt(),StandardTools.escapeDBString(structureRow),modelKey);
				executeNonQuery(insertStatement);
			}
			catch (Exception e)
			{
				java.io.StringWriter traceText = new java.io.StringWriter();
				java.io.PrintWriter pWriter = new java.io.PrintWriter(traceText,true);
				e.printStackTrace(pWriter);
				pWriter.close();
				
				String debugMessage; 
				debugMessage=String.format("Failure writting to database.\n Insert query was %1$s\n error is: %2$s", insertStatement,traceText.toString());
				throw new RuntimeException(debugMessage.toString());
			}
		}
		
		
		
		
		public Bundle[] selectAllStructures()
		{
			SQLiteCursor cursor=null;
			Bundle[] rows=new Bundle[0];
			int rowCount, counter=0;
			try
			{
				cursor = (SQLiteCursor)dataBase.query(r_TableName, r_SelectColumns, null, null, null, null, null);
				rowCount = cursor.getCount();
				if (rowCount>0)
				{
					rows = new Bundle[rowCount];
					while (cursor.moveToNext())
					{
						rows[counter]= new Bundle();
						rows[counter].putString("structure", cursor.getString(r_StructureColumnIndex));
						// TODO: Make this row index a resource
						rows[counter].putInt("model_id", cursor.getInt(1));
						counter++;
					}
				}
			}
			catch (Exception e)
			{
				Log.d("Inferece App",e.toString());
			}
			finally
			{
				if (cursor!=null)
					cursor.close();
			}
			return rows;
		}
	}
	

	
	private class TemplateTable
	{
		
		Resources resources;
		String r_CreateScript;
		String r_ClearTableScript;
		String r_InsertDataQuery;
		String r_TableName;
		String r_DeleteLabelSQL;
		String r_LabelWhereSQL;
		String[] selectColumns;
		int r_QueryTypeIndex;
		int r_FactTypeIndex;
		Hashtable<String, Integer> columnIndexMap;
		
		public TemplateTable()
		{
			resources=context.getResources();
			r_QueryTypeIndex=resources.getInteger(R.integer.template_query_index);
			r_FactTypeIndex=resources.getInteger(R.integer.template_fact_index);
			r_CreateScript = resources.getString(R.string.template_tb_create_sql);
			r_ClearTableScript=resources.getString(R.string.template_tb_drop_sql);
			r_InsertDataQuery = resources.getString(R.string.template_insert_sql);
			r_DeleteLabelSQL = resources.getString(R.string.template_delete_template_sql);
			r_TableName = resources.getString(R.string.template_tb_name);
			r_LabelWhereSQL = resources.getString(R.string.template_select_label_row_where_sql);
			loadIndexMap();
		}
		
		public void create()
		{
			executeNonQuery(r_CreateScript);
		}
		
		public void clear()
		{
			executeNonQuery(r_ClearTableScript);
		}
		
		public void insertData(int structureType, String label, String structureRow,boolean exportToStackP, String exportData )
		{
			String insertStatement = String.format(r_InsertDataQuery,structureType,exportToStackP?1:0,label, structureRow, isNull(exportData));
			executeNonQuery(insertStatement);
		}
		
		public Bundle[] selectAllData()
		{
			SQLiteCursor cursor=null;
			Bundle[] rows=new Bundle[0];
			int rowCount, counter=0;
			try
			{
				cursor = (SQLiteCursor)dataBase.query(r_TableName, selectColumns, null, null, null, null, null);
				rowCount = cursor.getCount();
				if (rowCount>0)
				{
					rows = new Bundle[rowCount];
					while (cursor.moveToNext())
					{
						rows[counter] = new Bundle();
						rows[counter].putBoolean("export_to_stack", mapTableValueToInt(cursor.getInt(columnIndexMap.get("export_to_stack"))));
						rows[counter].putInt("type", cursor.getInt(columnIndexMap.get("type")));
						rows[counter].putString("structure", cursor.getString(columnIndexMap.get("structure")));
						rows[counter].putString("label", cursor.getString(columnIndexMap.get("label")));
						rows[counter].putString("export_data", cursor.getString(columnIndexMap.get("export_data")));
						counter++;
					}
				}
			}
			catch (Exception e)
			{
				Log.d("Inferece App",e.toString());
				throw new RuntimeException(e.toString());
			}
			finally
			{
				if (cursor!=null)
					cursor.close();
			}
			return rows;
		}
		
		public Bundle[] selectLabelData(String label)
		{
			SQLiteCursor cursor=null;
			Bundle[] rows=new Bundle[0];
			int rowCount, counter=0;
			String effectiveSQL = String.format(r_LabelWhereSQL, label);
			try
			{
				cursor = (SQLiteCursor)dataBase.query(r_TableName, selectColumns, effectiveSQL, null, null, null, null);
				rowCount = cursor.getCount();
				if (rowCount>0)
				{
					rows = new Bundle[rowCount];
					while (cursor.moveToNext())
					{
						rows[counter] = new Bundle();
						rows[counter].putBoolean("export_to_stack", mapTableValueToInt(cursor.getInt(columnIndexMap.get("export_to_stack"))));
						rows[counter].putInt("type", cursor.getInt(columnIndexMap.get("type")));
						rows[counter].putString("structure", cursor.getString(columnIndexMap.get("structure")));
						rows[counter].putString("label", cursor.getString(columnIndexMap.get("label")));
						rows[counter].putString("export_data", cursor.getString(columnIndexMap.get("export_data")));
						counter++;
					}
				}
			}
			catch (Exception e)
			{
				Log.d("Inferece App",e.toString());
				throw new RuntimeException(e.toString());
			}
			finally
			{
				if (cursor!=null)
					cursor.close();
			}
			return rows;
		}
		
		public void deleteTemplate(String label)
		{
			String deleteStatement = String.format(r_DeleteLabelSQL,label);
			executeNonQuery(deleteStatement);
		}
		
		private void loadIndexMap()
		{
			columnIndexMap = new Hashtable<String, Integer>();
			int[] columnIndex;
			
			columnIndex = resources.getIntArray(R.array.template_column_indices);
			selectColumns = resources.getStringArray(R.array.db_template_column_names);
			int index=0;
			for (index=0;index<columnIndex.length;index++)
			{
				columnIndexMap.put(selectColumns[index], new Integer(columnIndex[index]));
			}
		}
		
		private int mapColumn(String columnName)
		{
			Integer i = columnIndexMap.get(columnName);
			if (i==null)
				return -1;
			return i.intValue();
		}
		

	}
	
	private void executeNonQuery(String query)
	{
		try
		{
			dataBase.execSQL(query);
		}
		catch (Exception e)
		{
			Log.d("Inferece App",e.toString());
			throw  new RuntimeException(e.toString());
		}
	}
	
	private static String isNull(String data)
	{
		return (data==null)?"":data;
	}
	
	private static int mapBooleanToTableValue(boolean value)
	{
		return (value)?1:0;
	}
	
	private static boolean mapTableValueToInt(int tValue)
	{
		return (tValue==0)?false:true;
	}
	
	
}
